using System;
using System.Linq;
using Microsoft.Practices.Unity;
using SDCloudSolution.SDCloud.BusinessLayer.Interfaces;
using SDCloudSolution.SDCloud.DataLayer.Interfaces;
using SDCloudSolution.SDCloud.DataLayer.ModelData;
using SDCloudSolution.SDCloud.DataLayer.ModelData.Interfaces;
using SDCloudSolution.SDCloud.DataLayer.MongoDb.Interfaces;
using SDCloudSolution.SDCloud.Web.Controllers;
using SDCloudSolution.SDCloud.Web.IoC;

namespace SDCloudSolution.SDCloud.Web
{
    /// <summary>
    /// Specifies the Unity configuration for the main container.
    /// </summary>
    public class UnityConfig
    {
        #region Unity Container

        private static readonly Lazy<IUnityContainer> _container = new Lazy<IUnityContainer>(() =>
        {
            var container = new UnityContainer();
            RegisterTypes(container);
            return container;
        });

        /// <summary>
        /// Gets the configured Unity container.
        /// </summary>
        public static IUnityContainer GetConfiguredContainer()
        {
            return _container.Value;
        }

        #endregion

        /// <summary>Registers the type mappings with the Unity container.</summary>
        /// <param name="container">The unity container to configure.</param>
        /// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to 
        /// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
        public static void RegisterTypes(IUnityContainer container)
        {
            RegisterTypesByPatter(container);

            container.RegisterType<IModelExecutionResultDataProvider, MongoModelExecutionResultDataProvider>();

            container.RegisterType<MongoModelMetadataDataProvider>();

            container.RegisterType<AccountController>(new PerResolveLifetimeManager());
            container.RegisterType<ModelRunsController>(new PerResolveLifetimeManager());
            container.RegisterType<LayoutController>(new PerResolveLifetimeManager());

            RegisterConfigurations(container);
        }

        private static void RegisterConfigurations(IUnityContainer container)
        {
            container.RegisterType<IIdentityDbConnectionStringProvider, ApplicationSettingsProvider>();
            container.RegisterType<IFileStorageSettingsProvider, ApplicationSettingsProvider>();
            container.RegisterType<ISdCloudMongoDbSettingsProvider, ApplicationSettingsProvider>();
        }

        private static void RegisterTypesByPatter(IUnityContainer container)
        {
            const string matchingSdCloudPattern = "SDCloudSolution.SDCloud";

            container.RegisterTypes(
                AllClasses.FromLoadedAssemblies()
                    .Where(assembly =>
                        !string.IsNullOrWhiteSpace(assembly.Namespace) &&
                        assembly.Namespace.Contains(matchingSdCloudPattern)),
                WithMappings.FromMatchingInterface,
                WithName.Default,
                WithLifetime.Custom<PerRequestLifetimeManager>);
        }
    }
}
